package com.youlai.system.controller.device;

import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.base.Joiner;
import com.youlai.system.common.result.PageResult;
import com.youlai.system.common.result.Result;
import com.youlai.system.mqtt.MqttSubClient;
import com.youlai.system.pojo.entity.device.DeviceConfigEntity;
import com.youlai.system.pojo.entity.device.DeviceInfoEntity;
import com.youlai.system.pojo.entity.device.DeviceUserRelEntity;
import com.youlai.system.pojo.entity.device.UserEntity;
import com.youlai.system.pojo.form.DeviceDetailVo;
import com.youlai.system.pojo.form.DeviceForm;
import com.youlai.system.pojo.query.DevicePageQuery;
import com.youlai.system.pojo.vo.device.DevicePageVO;
import com.youlai.system.service.impl.device.DeviceConfigService;
import com.youlai.system.service.impl.device.DeviceService;
import com.youlai.system.service.impl.device.DeviceUserRelService;
import com.youlai.system.service.impl.device.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Tag(name = "10.设备接口")
@RestController
@RequestMapping("/api/v1/device")
@RequiredArgsConstructor
public class DeviceController {

    @Autowired
    private DeviceService deviceService;


    private final DeviceUserRelService deviceUserRelService;

    private final UserService userService;

    private final DeviceConfigService deviceConfigService;

    private final MqttSubClient mqttSubClient;

    @Operation(summary = "删除设备", security = {@SecurityRequirement(name = "Authorization")})
    @GetMapping("/delete")
    @DeleteMapping("/delete")
    public Result<Boolean> deleteDeviceId(Integer deviceId){
        deviceService.deleteDeviceId(deviceId);
        return Result.success(Boolean.TRUE);
    }


    @Operation(summary = "设备分页列表", security = {@SecurityRequirement(name = "Authorization")})
    @GetMapping("/page")
    public PageResult<DevicePageVO> getDevicePage(
            DevicePageQuery queryParams
    ) {
        IPage<DevicePageVO> result = deviceService.getDevicePage(queryParams);
        return PageResult.success(result);
    }

    @GetMapping("/list")
    public Result<List<DeviceInfoEntity>> list() {

        List<DeviceInfoEntity> deviceInfoEntities = deviceService.list();

        return Result.success(deviceInfoEntities);
    }

    @Operation(summary = "设备配置详情", security = {@SecurityRequirement(name = "Authorization")})
    @GetMapping("/config/{deviceId}")
    public Result<DeviceConfigEntity> config(@PathVariable Integer deviceId) {
        DeviceConfigEntity deviceConfigEntity = new DeviceConfigEntity();
        LambdaQueryWrapper<DeviceConfigEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DeviceConfigEntity::getDeviceId, deviceId);

        List<DeviceConfigEntity> deviceConfigEntities = deviceConfigService.list(lambdaQueryWrapper);
        if (CollectionUtils.isNotEmpty(deviceConfigEntities)) {
            deviceConfigEntity = deviceConfigEntities.get(0);
        } else {
            deviceConfigEntity.setDeviceId(deviceId);
            deviceConfigEntity.setCjGap(10);
            deviceConfigEntity.setRecordGap(10);
            deviceConfigEntity.setWaveGap(10);
            deviceConfigEntity.setLimitDownWarn(10);
            deviceConfigEntity.setLimitUpWarn(10);
            deviceConfigEntity.setReportGap(100);


        }

        return Result.success(deviceConfigEntity);

    }

    @Operation(summary = "设备详情", security = {@SecurityRequirement(name = "Authorization")})
    @GetMapping("/{deviceId}/form")
    public Result<DeviceDetailVo> form(@PathVariable Integer deviceId) {
        DeviceInfoEntity deviceInfoEntity = deviceService.getById(deviceId);

        DeviceDetailVo deviceDetailVo = new DeviceDetailVo();

        deviceDetailVo.setId(deviceInfoEntity.getId());
        deviceDetailVo.setName(deviceInfoEntity.getName());
        deviceDetailVo.setMac(deviceInfoEntity.getMac());
        deviceDetailVo.setSimMobile(deviceInfoEntity.getSimMobile());

        LambdaQueryWrapper<DeviceUserRelEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DeviceUserRelEntity::getDeviceId, deviceId);

        List<DeviceUserRelEntity> deviceUserRelEntityList = deviceUserRelService.list(lambdaQueryWrapper);

        List<Integer> userIds = deviceUserRelEntityList.stream()
                .map(DeviceUserRelEntity::getUserId)
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(userIds)) {
            List<UserEntity> userEntities = userService.listByIds(userIds);

            List<String> phoneList = userEntities.stream()
                    .map(UserEntity::getPhone).collect(Collectors.toList());


            deviceDetailVo.setOwnPhones(
                    Joiner.on(",").join(phoneList)
            );

        }

        return Result.success(deviceDetailVo);
    }

    @PostMapping("/add")
    public Result<Boolean> add(@RequestBody DeviceForm deviceForm) {
        DeviceInfoEntity deviceInfoEntity = new DeviceInfoEntity();

        deviceInfoEntity.setMac(deviceForm.getMac());
        deviceInfoEntity.setOnlineStatus(0);
        deviceInfoEntity.setName(deviceForm.getName());
        deviceInfoEntity.setSimMobile(deviceForm.getSimMobile());
        deviceService.save(deviceInfoEntity);

        Integer deviceId = deviceInfoEntity.getId();

        dealRelation(deviceId, deviceForm.getOwnPhones());

        createDeviceConfig(deviceInfoEntity);

        return Result.success(Boolean.TRUE);
    }

    private void createDeviceConfig(DeviceInfoEntity deviceInfoEntity) {

        LambdaQueryWrapper<DeviceConfigEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DeviceConfigEntity::getDeviceId, deviceInfoEntity.getId());

        Long count = deviceConfigService.count(lambdaQueryWrapper);

        if(count == 0){
            DeviceConfigEntity deviceConfigEntity = new DeviceConfigEntity();
            deviceConfigEntity.setDeviceId(deviceInfoEntity.getId());
            deviceConfigEntity.setLimitDownWarn(10);
            deviceConfigEntity.setK("11");
            deviceConfigEntity.setReportGap(15);
            deviceConfigEntity.setRecordGap(15);
            deviceConfigEntity.setCjGap(15);
            deviceConfigEntity.setLimitDownWarn(1);
            deviceConfigEntity.setWarnPhone("18905868165");

            deviceConfigService.save(deviceConfigEntity);
        }


    }

    @PostMapping("/updateConfig/{deviceId}")
    public Result<Boolean> updateConfig(@RequestBody DeviceConfigEntity form, @PathVariable Integer deviceId) {

        LambdaQueryWrapper<DeviceConfigEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DeviceConfigEntity::getDeviceId, deviceId);

        List<DeviceConfigEntity> deviceConfigEntities = deviceConfigService.list(lambdaQueryWrapper);
        Integer deviceConfigId = null;
        if (CollectionUtils.isNotEmpty(deviceConfigEntities)) {
            deviceConfigId = deviceConfigEntities.get(0).getId();
        }
        DeviceConfigEntity deviceConfigEntity = new DeviceConfigEntity();

        BeanUtils.copyProperties(form, deviceConfigEntity);
        deviceConfigEntity.setId(deviceConfigId);

        deviceConfigService.saveOrUpdate(deviceConfigEntity);
        DeviceInfoEntity deviceInfoEntity = deviceService.getById(deviceId);
        {

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("sample_nterval", deviceConfigEntity.getCjGap());
            jsonObject.put("record", deviceConfigEntity.getRecordGap());
            jsonObject.put("down_nterval", deviceConfigEntity.getReportGap());
            jsonObject.put("fluctuate", deviceConfigEntity.getWaveGap());
            jsonObject.put("floor", deviceConfigEntity.getLimitDownWarn());
            jsonObject.put("upper", deviceConfigEntity.getLimitUpWarn());

            mqttSubClient.send("/down/set/" + deviceInfoEntity.getMac(), jsonObject.toJSONString());

        }

        {

            JSONObject property = new JSONObject();
            property.put("hight", deviceConfigEntity.getHeight());
            property.put("k", deviceConfigEntity.getK());
            property.put("b", deviceConfigEntity.getT());
            property.put("Q0", deviceConfigEntity.getQ());

            mqttSubClient.send("/down/property/" + deviceInfoEntity.getMac(), property.toJSONString());

        }

        return Result.success(Boolean.TRUE);

    }

    @PostMapping("/update/{deviceId}")
    public Result<Boolean> update(@RequestBody DeviceForm deviceForm, @PathVariable Integer deviceId) {
        DeviceInfoEntity deviceInfoEntity = new DeviceInfoEntity();
        deviceInfoEntity.setId(deviceId);
        deviceInfoEntity.setMac(deviceForm.getMac());
        deviceInfoEntity.setName(deviceForm.getName());
        deviceInfoEntity.setSimMobile(deviceForm.getSimMobile());
        deviceService.updateById(deviceInfoEntity);

        dealRelation(deviceId, deviceForm.getOwnPhones());

        return Result.success(Boolean.TRUE);

    }

    private void dealRelation(Integer deviceId, String ownPhones) {
        if (StringUtils.isEmpty(ownPhones)) {
            return;
        }
        LambdaUpdateWrapper<DeviceUserRelEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();

        lambdaUpdateWrapper.eq(DeviceUserRelEntity::getDeviceId, deviceId);

        deviceUserRelService.remove(lambdaUpdateWrapper);

        List<String> phoneList = Arrays.stream(ownPhones.split(",")).collect(Collectors.toList());

        LambdaQueryWrapper<UserEntity> userEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userEntityLambdaQueryWrapper.in(UserEntity::getPhone, phoneList);

        List<UserEntity> userEntities = userService.list(userEntityLambdaQueryWrapper);

        List<DeviceUserRelEntity> userRelEntities = userEntities.stream()
                .map(userEntity -> {
                    DeviceUserRelEntity deviceUserRelEntity = new DeviceUserRelEntity();
                    deviceUserRelEntity.setDeviceId(deviceId);
                    deviceUserRelEntity.setUserId(userEntity.getId());
                    deviceUserRelEntity.setCreateTime(new DateTime());
                    deviceUserRelEntity.setLastUpdateTime(new DateTime());
                    return deviceUserRelEntity;
                }).collect(Collectors.toList());
        deviceUserRelService.saveBatch(userRelEntities);

    }
}
